home *** CD-ROM | disk | FTP | other *** search
/ Nebula 2 / Nebula Two.iso / SourceCode / GameKit / gamekit-1 / HighScoreTable.m < prev    next >
Text File  |  1995-06-12  |  6KB  |  214 lines

  1.  
  2. #import <stdio.h>        // strcpy
  3. #import <stdlib.h>        // malloc
  4. #import <strings.h>
  5. #import <objc/typedstream.h>    // highscore tables
  6. #import <daymisckit/daymisckit.h>
  7. #import <gamekit/gamekit.h>
  8. #import <appkit/appkit.h>
  9. #import <remote/NXProxy.h>
  10.  
  11.  
  12. @implementation HighScoreTable
  13.  
  14. - init        // designated initializer sets up game variables
  15. {        // to sensible values.
  16.     [super init];
  17.     tag = 0;
  18.     title = [[DAYString alloc] init];
  19.     emptySlot = [[HighScoreSlot alloc] init]; // ***** use proper class
  20.     maxHighScores = MAXSCORES;
  21.     return self;
  22. }
  23.  
  24. - setEmptySlotClass:classObject
  25. {
  26.     if (emptySlot) [emptySlot free];
  27.     emptySlot = [[classObject alloc] init];
  28.     return self;
  29. }
  30.  
  31. - setStringValue:(const char *)aString
  32. {
  33.     [title setStringValue:aString];
  34.     return self;
  35. }
  36.  
  37. - (BOOL)samePlayer:slot1 :slot2
  38. {    // if the login names are same, assume same user.  You can override this
  39.     // to go by machine name or whatever.
  40.     if (![slot1 userName] || ![slot2 userName]) return NO;
  41.     if (strcmp([slot1 userName], [slot2 userName])) return NO;
  42.     return YES;
  43. }
  44.  
  45. - (int)numEntriesByPlayer:aSlot // return # of high scores player has
  46. {
  47.     int i, count = 0;
  48.     for (i=0; i<[self count]; i++)
  49.         if ([self samePlayer:[self objectAt:i] :aSlot]) count++;
  50.     return count;
  51. }
  52.  
  53. - (int)lowestSlotByPlayer:aSlot // return lowest scoring slot by player
  54. {
  55.     int i;
  56.     // look for appropriate slot from end of list to front
  57.     for (i=[self count]-1; i>=0; i--)
  58.         if ([self samePlayer:[self objectAt:i] :aSlot])
  59.             return i;
  60.     // return [self count] if didn't find a slot that matches criteria
  61.     return [self count];
  62. }
  63.  
  64. - (const char *)stringValue { return [title stringValue]; }
  65. - (int)tag    { return tag; }
  66. - setTag:(int)newTag { tag = newTag; return self; }
  67. - (int)maxHighScores { return maxHighScores; }
  68. - setMaxHighScores:(int)newMax
  69. {
  70.     maxHighScores = newMax;
  71.     return self;
  72. }
  73.  
  74. - (int)maxScoresPerPlayer { return maxScoresPerPlayer; }
  75. - setMaxScoresPerPlayer:(int)newMax
  76. {
  77.     maxScoresPerPlayer = newMax;
  78.     return self;
  79. }
  80.  
  81. - (BOOL)addSlot:newSlot // keeps the table sorted as slots are added.
  82. {
  83.     int i;
  84.     return [self addSlot:newSlot where:&i];
  85. }
  86.  
  87. - (BOOL)addSlot:newSlot where:(int *)w // keeps table sorted as slots added.
  88. {    // the key for the sort is from slots' -isAbove method...
  89.     int i; id xtraObj;
  90.     for (i=0; i<[self count]; i++) {    // find where to add slot
  91.         if ([newSlot isAbove:[self objectAt:i]]) break;
  92.     } // insert it
  93.     [self insertObject:newSlot at:i]; // insert regardless
  94.     if (maxScoresPerPlayer) { // 0 == unlimited entries
  95.         if ([self numEntriesByPlayer:newSlot] > maxScoresPerPlayer) {
  96.             // have one more entry by this player than allowed, so
  97.             // we'll delete the lowest.
  98.             int xtraSlotNum = [self lowestSlotByPlayer:newSlot];
  99. #ifdef NOISYDEBUG
  100.             fprintf(stderr,
  101.                 "HighScoreTable:  removing extra entry by player %s.\n",
  102.                 [newSlot userName]);
  103. #endif
  104.             // delete the actual slot and free it.
  105.             xtraObj = [self removeObject:[self objectAt:xtraSlotNum]];
  106.             if ([xtraObj isProxy]) [xtraObj freeProxy];
  107.             else [xtraObj free];
  108.             // if this was the slot we just added, then return
  109.             // that we didn't add it after all...
  110.             if (i == xtraSlotNum) {
  111.                 *w = [self count];
  112.                 return NO;
  113.             }
  114.         }
  115.     }
  116.     // prune the table so it doesn't grow too big.  max # is set by init.
  117.     // done by deleting slots from the end to the front until size is OK.
  118.     while ([self count] > maxHighScores) {
  119.             xtraObj = [self removeLastObject];
  120.             if ([xtraObj isProxy]) [xtraObj freeProxy];
  121.             else [xtraObj free];
  122.     }
  123.     *w = i;    // return by reference where we added it.
  124.     if (i >= maxHighScores) return NO;
  125.     return YES;
  126. }
  127.  
  128. - objectAt:(unsigned)index
  129. {
  130.     if (index >= [self count]) return emptySlot;
  131.     return [super objectAt:index];
  132. }
  133.  
  134. - free
  135. {
  136.     [emptySlot free];
  137.     return [super free];
  138. }
  139.  
  140. - copy
  141. {    // build a new table with new slots (i.e. don't just copy id pointers,
  142.     // actually make new objects)
  143.     int i; id aCopy = [[[self class] alloc] init];
  144.     [aCopy setEmptySlotClass:[emptySlot class]];
  145.     [aCopy setMaxHighScores:maxHighScores];
  146.     for (i=0; i<[self count]; i++) {
  147.         [aCopy addSlot:[[self objectAt:i] copy]];
  148.     }
  149.     return aCopy;
  150. }
  151.  
  152. - read:(NXTypedStream *)stream
  153. { // don't save emptySlot since it is easy enough to create
  154.     [super read:stream];
  155.     NXReadTypes(stream, "iii", &maxHighScores, &maxScoresPerPlayer, &tag);
  156.     emptySlot = NXReadObject(stream);
  157.     title = NXReadObject(stream);
  158.     return self;
  159. }
  160.  
  161. - write:(NXTypedStream *)stream
  162. {
  163.     [super write:stream];
  164.     NXWriteTypes(stream, "iii", &maxHighScores, &maxScoresPerPlayer, &tag);
  165.     NXWriteObject(stream, emptySlot); // saved to preserve class type
  166.     NXWriteObject(stream, title);
  167.     return self;
  168. }
  169.  
  170. // NXTransport protocol implementation:  List must contain objects that
  171. // also use this protocol; otherwise it won't xfer by copy properly!
  172. - encodeUsing:(id <NXEncoding>)portal
  173. {
  174.     int i, n = [self count];
  175.     [portal encodeData:&n ofType:"i"];
  176.     [portal encodeData:&maxHighScores ofType:"i"];
  177.     [portal encodeData:&maxScoresPerPlayer ofType:"i"];
  178.     [portal encodeData:&tag ofType:"i"];
  179.     for (i=0; i<n; i++) {
  180.             [portal encodeObjectBycopy:[self objectAt:i]];
  181.     }
  182.     [portal encodeObjectBycopy:emptySlot];
  183.     [portal encodeObjectBycopy:title];
  184.     return self;
  185. }
  186.  
  187. - decodeUsing:(id <NXDecoding>)portal
  188. {
  189.     int i, n;
  190.     [portal decodeData:&n ofType:"i"];
  191.     [portal decodeData:&maxHighScores ofType:"i"];
  192.     [portal decodeData:&maxScoresPerPlayer ofType:"i"];
  193.     [portal decodeData:&tag ofType:"i"];
  194.     [self freeObjects]; // make sure that we're empty
  195.     for (i=0; i<n; i++) {
  196.             [self addObject:[portal decodeObject]];
  197.     }
  198.     emptySlot = [portal decodeObject];
  199.     title = [portal decodeObject];
  200.     return self;
  201. }
  202.  
  203. - encodeRemotelyFor:(NXConnection *)connection
  204.     freeAfterEncoding:(BOOL *)flagp isBycopy:(BOOL)isByCopy
  205. {
  206.     if (isByCopy) return self; //encode object (copy it)
  207.     // super will encode the proxy otherwise
  208.     return [super encodeRemotelyFor:connection
  209.                 freeAfterEncoding:flagp isBycopy:isByCopy];
  210. }
  211.  
  212.  
  213. @end
  214.